package com.upcode.weighing.oauthserver.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Sets;
import com.upcode.weighing.domain.AppUser;
import com.upcode.weighing.domain.DetectPoint;
import com.upcode.weighing.domain.SysUser;
import com.upcode.weighing.mapper.DetectPointMapper;
import com.upcode.weighing.oauthserver.dto.UserInfoDTO;
import com.upcode.weighing.oauthserver.mapper.SysUserOauthMapper;
import com.upcode.weighing.oauthserver.mapper.UserOauthMapper;
import com.upcode.weighing.oauthserver.util.OauthConstants;
import com.upcode.weighing.util.SensitiveInfoUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;


/**
 * @author zhuyanwei
 */
@Service("userDetailsService")
public class DomainUserDetailsServiceImpl implements UserDetailsService {
    private static final Logger logger= LoggerFactory.getLogger(DomainUserDetailsServiceImpl.class);
    @Value("${multipe-login-phone}")
    private String multipeLoginPhoneStr;
    private List<String> multipeLoginPhone;
    @Value("${password-strength}")
    private boolean passwordStrength;

    @Autowired
    private SysUserOauthMapper sysUserMapper;
    @Autowired
    private UserOauthMapper userMapper;
    @Autowired
    private DetectPointMapper detectPointMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private SysOptLogRecService sysOptLogService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private AuthService authService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User userInfo = (User) authentication.getPrincipal();

        String password = request.getParameter("password");

      /*  String redisKeyTen = "locking:ten:" + username + "";
        String jsonStrTen = stringRedisTemplate.boundValueOps(redisKeyTen).get();
        Integer lockingNumTen = StringUtils.isBlank(jsonStrTen) ? 0 : Integer.valueOf(jsonStrTen);
        if (lockingNumTen >= 10) {
            throw new UsernameNotFoundException("登录失败超过10次，账户已被锁定，请24小时后重试。");
        }
        String redisKeyThree = "locking:three:" + username + "";
        String jsonStrThree = stringRedisTemplate.boundValueOps(redisKeyThree).get();
        Integer lockingNumThree = StringUtils.isBlank(jsonStrThree) ? 0 : Integer.valueOf(jsonStrThree);
        if (lockingNumThree >= 3) {
            throw new UsernameNotFoundException("登录失败超过3次，账户已被锁定，请10分钟后重试。");
        }*/
        //手机端密码登陆用户
        if (StringUtils.equals(OauthConstants.CLIENT_ID_MOBILE, userInfo.getUsername())) {
//            Integer loginLag = Integer.parseInt(request.getParameter("flag"));
            QueryWrapper<AppUser> userEntityWrapper = new QueryWrapper<>();
            userEntityWrapper.eq("mobile_no", username);
            Integer[] i = {0, 1, 2};
            userEntityWrapper.in("status", i);
            List<AppUser> userList = userMapper.selectList(userEntityWrapper);
            if (userList == null || userList.isEmpty()) {
              /*  stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);*/
                throw new UsernameNotFoundException("用户名或密码不正确");
            }
            if (userList.size() > 1) {
               /* stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);*/
                throw new UsernameNotFoundException("用户名或密码不正确");
            }
            AppUser user = userList.get(0);
            if (user.getStatus() == 1) { //用户被禁用
              /*  stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);*/
                throw new UsernameNotFoundException(user.getDisableReason());
            }
            checkPassword(user.getPassword(), password);
            //authService.cleanToken(username,"1");
            /*logger.debug("multipeLoginPhoneStr:"+multipeLoginPhoneStr);
            if(multipeLoginPhone==null){
                String[] strs=multipeLoginPhoneStr.split(",");
                multipeLoginPhone = Arrays.asList(strs);
            }*/
            //强制当前登录用户下线
            /*if(!multipeLoginPhone.contains(username)){
                authService.logOut(username,"2");
            }*/
            Set<GrantedAuthority> authorities = Sets.newHashSet();
            UserInfoDTO dto;
            //数据脱敏 -- 姓名
            user.setName(SensitiveInfoUtils.sensitiveName(user.getName()));
            user.setMobileNo(SensitiveInfoUtils.sensitiveTel(user.getMobileNo()));
            user.setIdcardNo(SensitiveInfoUtils.sensitiveIdCard(user.getIdcardNo()));
//            if (0 == loginLag) { //微信小程序登录
//                dto = new UserInfoDTO(String.valueOf(user.getId()), user.getName(), user.getMobileNo(), user.getWxPassword(), user.getIdcardNo(), user.getPhotoAddr(),authorities);
//            }else { //app登录
            dto = new UserInfoDTO(String.valueOf(user.getId()), user.getName(), user.getMobileNo(), user.getPassword(), user.getIdcardNo(), user.getPhotoAddr(), authorities);
//            }
            return dto;
        } else if (StringUtils.equals(OauthConstants.CLIENT_ID_VERIFICATION, userInfo.getUsername())) { //手机端验证码登陆用户
            QueryWrapper<AppUser> userEntityWrapper = new QueryWrapper<>();
            userEntityWrapper.eq("mobile_no", username);
            Integer[] i = {0, 1, 2};
            userEntityWrapper.in("status", i);
            List<AppUser> userList = userMapper.selectList(userEntityWrapper);
            if (userList == null || userList.isEmpty()) {
//                throw new UsernameNotFoundException("用户" + username + "不存在!");
                throw new UsernameNotFoundException("用户名或密码不正确");
            }
            if (userList.size() > 1) {
//                throw new UsernameNotFoundException("用户" + username + "不唯一!");
                throw new UsernameNotFoundException("用户名或密码不正确");
            }
            AppUser user = userList.get(0);
            if (user.getStatus() == 0) {
                throw new UsernameNotFoundException(user.getDisableReason());
            }
            Set<GrantedAuthority> authorities = Sets.newHashSet();
            String d = stringRedisTemplate.boundValueOps(username).get();
            if (null == d) {
                throw new UsernameNotFoundException("短信验证码已失效");
            }
            //authService.cleanToken(username,"2");
            //强制当前登录用户下线
            authService.logOut(username);
            return new UserInfoDTO(String.valueOf(user.getId()), user.getName(), user.getMobileNo(), new BCryptPasswordEncoder().encode(d), authorities);
        } else if (StringUtils.equals(OauthConstants.CLIENT_ID_WEBAPP, userInfo.getUsername())) {//管理后台
            //bugFix 121 modified by LeiDong 账号停用时登录提示”账号已被停用，请联系系统管理员启用账号"
            QueryWrapper<SysUser> wrapperInfo = new QueryWrapper<>();
            wrapperInfo.eq("login_name", username);
            wrapperInfo.eq("status", "0");
            List<SysUser> sysUser = sysUserMapper.selectList(wrapperInfo);
            if (sysUser != null) {
                for (SysUser s : sysUser) {
                    if (s.getLoginName().equals(username)) {
                        throw new UsernameNotFoundException("账号已被停用，请联系系统管理员启用账号。");
                    }
                }
            }
            //bugFix 121
            QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
            wrapper.eq("login_name", username);
//            wrapper.eq("type", "1");
            wrapper.eq("status", "1");
            List<SysUser> userList = sysUserMapper.selectList(wrapper);
            if (userList == null || userList.isEmpty()) {
//                stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
//                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);
                throw new UsernameNotFoundException("用户名或密码不正确");
            }

            if (userList.size() > 1) {
//                stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
//                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);
                throw new UsernameNotFoundException("用户名或密码不正确");
            }

            SysUser user = userList.get(0);
            //比对密码以及校验密码强度
            checkPassword(user.getPwd(), password);

//        List<AuthMarkingDTO> auths = sysUserMapper.findAuthMarkingByUserId(user.getId());
            Set<GrantedAuthority> authorities = Sets.newHashSet();
//        if(auths != null && !auths.isEmpty()) {
//            for(AuthMarkingDTO authMarking : auths) {
//                authorities.add(new SimpleGrantedAuthority(authMarking.getAuthRole()));
//                authorities.add(new SimpleGrantedAuthority(authMarking.getPermission()));
//            }
//        }
            sysOptLogService.addSysLoginLog(user.getLoginName(), request);
            return new UserInfoDTO(String.valueOf(user.getId()), user.getName(), user.getLoginName(), user.getPwd(), authorities);
        }else if(StringUtils.equals(OauthConstants.DETECT_DEVICE, userInfo.getUsername())){
            QueryWrapper<DetectPoint> userEntityWrapper = new QueryWrapper<>();
            userEntityWrapper.eq("point_no", username);
            List<DetectPoint> userList = detectPointMapper.selectList(userEntityWrapper);
            if (userList == null || userList.isEmpty()) {
//                stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree + 1), 10, TimeUnit.MINUTES);
//                stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen + 1), 24, TimeUnit.HOURS);
                throw new UsernameNotFoundException("检测点编号不正确");
            }
            DetectPoint user = userList.get(0);
            if(!user.getUploadAuthCode().equals(password)){
                throw new UsernameNotFoundException("密码不正确,请联系管理员");
            }
            Set<GrantedAuthority> authorities = Sets.newHashSet();
            UserInfoDTO dto;
            dto = new UserInfoDTO(String.valueOf(user.getId()), user.getPointNo(),user.getName(), new BCryptPasswordEncoder().encode(user.getUploadAuthCode()), authorities);
            return dto;
        }else{
            return null;
        }
    }

    /**
     * 添加系统用户登陆日志
     * @param
     */
//    private void addSysLoginLog(String user){
//
//        SysLog sysLog = new SysLog();
//        Date date = new Date();
//        String ip = ClientRequestInfoUtil.getClientIp(request);
//        String browser = ClientRequestInfoUtil.getBrowser(request);
//        String area = "";
//        if(!ip.isEmpty()){
//            area = ClientRequestInfoUtil.getIpInfo(ip);
//        }
//
//        sysLog.setId(IdWorker.getId());
//        sysLog.setCreateUser(user);
//        sysLog.setAdr(ip);
//        sysLog.setDesc(browser);
//        sysLog.setCreateTime(date);
//        sysLog.setStatus(1);
//        sysLog.setRemark(area);
//        sysLog.setType(5);
//        sysLogService.insert(sysLog);
//    }

    private void checkPassword(String myPassword,String password, String redisKeyThree, String redisKeyTen,
                               Integer lockingNumThree, Integer lockingNumTen ){
        //对比密码正确性
        boolean checkPwd =  new BCryptPasswordEncoder().matches(password,myPassword);
        if(!checkPwd){
            stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree+1),10, TimeUnit.MINUTES);
            stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen+1),24, TimeUnit.HOURS);
            throw new UsernameNotFoundException("用户名或密码不正确");
        }

        //判断密码强度
        if(passwordStrength){
            if(password.length() < 8){
                throw new UsernameNotFoundException("密码不正确,请联系管理员");
            }
            Pattern patternNum;
            patternNum = Pattern.compile("[0-9]*");
            boolean isNum = patternNum.matcher(password).find();
            Pattern patternLetter;
            patternLetter = Pattern.compile(".*[a-zA-Z]+.*");
            boolean isLetter = patternLetter.matcher(password).find();
            if(!isNum || !isLetter){
                throw new UsernameNotFoundException("密码不正确,请联系管理员");
            }
        }
    }

    private void checkPassword(String myPassword,String password){
        //对比密码正确性
        boolean checkPwd =  new BCryptPasswordEncoder().matches(password,myPassword);
       /* if(!checkPwd){
            stringRedisTemplate.boundValueOps(redisKeyThree).set(String.valueOf(lockingNumThree+1),10, TimeUnit.MINUTES);
            stringRedisTemplate.boundValueOps(redisKeyTen).set(String.valueOf(lockingNumTen+1),24, TimeUnit.HOURS);
            throw new UsernameNotFoundException("用户名或密码不正确");
        }*/

        //判断密码强度
        if(passwordStrength){
            if(password.length() < 8){
                throw new UsernameNotFoundException("密码不正确,请联系管理员");
            }
            Pattern patternNum;
            patternNum = Pattern.compile("[0-9]*");
            boolean isNum = patternNum.matcher(password).find();
            Pattern patternLetter;
            patternLetter = Pattern.compile(".*[a-zA-Z]+.*");
            boolean isLetter = patternLetter.matcher(password).find();
            if(!isNum || !isLetter){
                throw new UsernameNotFoundException("密码不正确,请联系管理员");
            }
        }
    }

}
